package com.yao2san.sim.storage.client.config;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.region.Region;
import com.yao2san.sim.storage.client.core.downloader.AliOssDownloader;
import com.yao2san.sim.storage.client.core.downloader.LocalDownloader;
import com.yao2san.sim.storage.client.core.downloader.MinioDownloader;
import com.yao2san.sim.storage.client.core.downloader.TencentCosDownloader;
import com.yao2san.sim.storage.client.core.integrate.IntegrateConfig;
import com.yao2san.sim.storage.client.core.integrate.IntegrateDownloader;
import com.yao2san.sim.storage.client.core.integrate.IntegrateStorageManager;
import com.yao2san.sim.storage.client.core.integrate.IntegrateUploader;
import com.yao2san.sim.storage.client.core.manager.AliOssStorageManager;
import com.yao2san.sim.storage.client.core.manager.LocalStorageManager;
import com.yao2san.sim.storage.client.core.manager.MinioStorageManager;
import com.yao2san.sim.storage.client.core.manager.TencentCosStorageManager;
import com.yao2san.sim.storage.client.core.policy.*;
import com.yao2san.sim.storage.client.core.uploader.*;
import io.minio.MinioClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ConditionalOnProperty(prefix = "sim.storage", name = "enable", havingValue = "true")
@Import({SimStorageClientProperties.class, MinioProperties.class, LocalProperties.class, IntegrateProperties.class, AliOssProperties.class, TencentCosProperties.class})
@ComponentScan("com.yao2san.sim.storage.client")
public class SimStorageClientConfig {

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "minio")
    @ConditionalOnMissingBean(MinioClient.class)
    public MinioClient minioClient(MinioProperties minioProperties) {
        return MinioClient.builder()
                .endpoint(minioProperties.getEndpoint())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "ali_oss")
    @ConditionalOnMissingBean(OSS.class)
    public OSS ossClient(AliOssProperties aliOssProperties) {
        return new OSSClientBuilder().build(aliOssProperties.getEndpoint(), aliOssProperties.getAccessKey(), aliOssProperties.getSecretKey());
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "tencent_cos")
    @ConditionalOnMissingBean(COSClient.class)
    public COSClient cosClient(TencentCosProperties tencentCosProperties) {
        COSCredentials cred = new BasicCOSCredentials(tencentCosProperties.getAccessKey(), tencentCosProperties.getSecretKey());
        Region region = new Region(tencentCosProperties.getRegion());
        ClientConfig clientConfig = new ClientConfig(region);
        clientConfig.setHttpProtocol(HttpProtocol.https);
        return new COSClient(cred, clientConfig);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "minio")
    public MinioUploader minioUploader(MinioClient client, MinioProperties minioProperties, ApplicationContext context, FolderPolicy folderPolicy) {
        return new MinioUploader(client, minioProperties, context, folderPolicy);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "local")
    public LocalUploader localUploader(LocalProperties localProperties, ApplicationContext context, FolderPolicy folderPolicy, FileRenamePolicy fileRenamePolicy) {
        return new LocalUploader(localProperties, context, folderPolicy, fileRenamePolicy);
    }


    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "ftp")
    public FtpUploader ftpUploader() {
        return new FtpUploader();
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "integrate")
    public IntegrateUploader integrateUploader(SimStorageClientProperties clientProperties, IntegrateConfig integrateConfig, ApplicationContext applicationContext, FolderPolicy folderPolicy, FileRenamePolicy fileRenamePolicy) {
        return new IntegrateUploader(clientProperties, integrateConfig, applicationContext, folderPolicy, fileRenamePolicy);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "ali_oss")
    public AliOssUploader aloOssUploader(OSS ossClient, AliOssProperties aliOssProperties, ApplicationContext applicationContext, FolderPolicy folderPolicy, FileRenamePolicy fileRenamePolicy) {
        return new AliOssUploader(ossClient, aliOssProperties, applicationContext, folderPolicy);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "tencent_cos")
    public TencentCosUploader tencentCosUploader(COSClient cosClient, TencentCosProperties tencentCosProperties, ApplicationContext applicationContext, FolderPolicy folderPolicy, FileRenamePolicy fileRenamePolicy) {
        return new TencentCosUploader(cosClient, tencentCosProperties, applicationContext, folderPolicy);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "integrate")
    public IntegrateConfig integrateConfig(IntegrateProperties integrateProperties) {
        return new IntegrateConfig(integrateProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "minio")
    public MinioDownloader minioDownloader(MinioClient client, MinioProperties minioProperties) {
        return new MinioDownloader(client, minioProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "local")
    public LocalDownloader localDownloader(LocalProperties localProperties) {
        return new LocalDownloader(localProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "integrate")
    public IntegrateDownloader integrateDownloader(SimStorageClientProperties clientProperties, IntegrateConfig integrateConfig) {
        return new IntegrateDownloader(clientProperties, integrateConfig);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "ali_oss")
    public AliOssDownloader aliOssDownloader(OSS ossClient, AliOssProperties clientProperties) {
        return new AliOssDownloader(ossClient, clientProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "tencent_cos")
    public TencentCosDownloader tencentCosDownloader(COSClient cosClient, TencentCosProperties clientProperties) {
        return new TencentCosDownloader(cosClient, clientProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "enable", havingValue = "true")
    @ConditionalOnMissingBean(FolderPolicy.class)
    public FolderPolicy folderPolicy() {
        return new EmptyFolderPolicy();
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "local")
    public LocalStorageManager localStorageManager(LocalProperties localProperties) {
        return new LocalStorageManager(localProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "minio")
    public MinioStorageManager minioStorageManager(MinioClient client, MinioProperties minioProperties) {
        return new MinioStorageManager(client, minioProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "ali_oss")
    public AliOssStorageManager aliOssStorageManager(OSS ossClient, AliOssProperties aliOssProperties) {
        return new AliOssStorageManager(ossClient, aliOssProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "tencent_cos")
    public TencentCosStorageManager tencentCosStorageManager(COSClient cosClient, TencentCosProperties tencentCosProperties) {
        return new TencentCosStorageManager(cosClient, tencentCosProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "sim.storage", name = "type", havingValue = "integrate")
    public IntegrateStorageManager integrateStorageManager(SimStorageClientProperties clientProperties, IntegrateConfig integrateConfig) {
        return new IntegrateStorageManager(clientProperties, integrateConfig);
    }

    @Bean
    @ConditionalOnMissingBean(SecurityPolicy.class)
    public SecurityPolicy securityPolicy() {
        return new EmptySecurityPolicy();
    }

    @Bean
    @ConditionalOnMissingBean(FileRenamePolicy.class)
    public FileRenamePolicy fileRenamePolicy() {
        return new EmptyFileRenamePolicy();
    }

    @Bean
    @ConditionalOnMissingBean(UploadNotifyHandlerPolicy.class)
    public UploadNotifyHandlerPolicy fileMetaHandlerPolicy() {
        return new EmptyUploadNotifyHandlerPolicy();
    }
}
